home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
130 MIDI Tool Box
/
130 MIDI Tool Box.iso
/
jay_midi
/
midi111.c
next >
Wrap
Text File
|
1986-06-03
|
38KB
|
1,283 lines
/* MIDInterface 1.11
Copyright (C) 1985, 1986 By:
Jay Kubicky
934 N. Orange St.
Media, PA 19063
215-565-7761
This is a VERY recent version of this program.
It has not been 'tested' extensively, though all testing that
has been done shows favorable results.
All users are free, of course, to test (and debug) this software as
desired.
This program was developed under the DeSmet C compiler, and utilizes
DeSmet's vastly useful in-line assembly language capability.
Compiling it on other compilers (such as Lattice) may require
EXTENSIVE modification.
2/14/86
*/
#define MIDID 0xffa0
#define MIDIS 0xffa2
#define PIC0 0x20
#define PIC1 0x21
#define CSTAT 0xFFA7
#define COUNTER1 0xFFA4
#define COUNTER2 0xFFA5
#define Tsize 25600 /* track size in bytes (24K) */
#define Tk 25 /* track size in K */
#define seg_per_trk 1600 /* track size in paragraphs */
/* the following structures hold data for each buffer */
char prog_id[]={"MIDInterface 1.11 (c) 1985, 1986 Jay Kubicky"};
struct rec { /* 63 bytes long 63*16=1008 bytes total */
char chan;
unsigned ssize;
char name[40];
char transpose; /* transpose amount */
char extra[19]; /* for later use */
} parts[16];
char in_filt; /* This is the MIDI input filter mask:
bit: message filtered out:
--- --------------------
0 Note ON
1 Note OFF
2 Program Change
3 Channel Pres. (After-touch)
4 Pitch Wheel
5 Control Change
6 Poly. Key pres. (After-touch)
*/
char on[4]="ON "; /* 'ON' */
char off[4]="OFF"; /* 'OFF' */
char yes[4]="YES";
char no[4]="NO ";
char sin_line[80]; /* A 79 char. single line */
unsigned r_segment;
char *ptr, *end;
int fd; char filename[30];
int r_tempo; /* tempo val (bpm) */
unsigned tempo; /* real tempo val. */
char destbyte, stop;
char clsb, cmsb, dsync, MIDIsync, audmet;
char rbuff; /* receive buffer */
char beat, mbeat,abeat, s_t_b, m_t_b, a_t_b; /* beats & time bases */
char buffon[16]; /* true means given buff is active */
unsigned pointers[16]; /* an array of pointers into present buffers */
unsigned startp[16]; /* an array of starts of present buffer */
unsigned endp[16]; /* pointers to end of songs */
unsigned segment[16]; /* array of segments of tracks */
int pfd; /* fd for printer */
char printer; /* printer enable */
extern unsigned _rax, _rbx, _rdx, _res, _rds;
char LAST_STAT;
char C_O_F;
char clk_type; /* 0=internal, 1=external */
char counter_dec;
char vir_buff[1024];
char buff1[Tsize]; /* track 0 - 3070 notes */
char buff2[Tsize]; /* track 1 - 3070 notes */
/* first two tracks eat up 50K */
/* last fourteen will take 350K combined */
/* total note storage=
3200 notes per track
51200 notes in all!!! */
char *_showsp(),*_showss(),*_showds();
main()
{
unsigned a;
char clkval,sel,b; int c;
unsigned base_seg, cont_mem;
/* the following code stores the DS at 0x4FA */
/* THIS IS VERY IMPORTANT!!!!!!!! */
/* this allows the DS to be transffered to the RXINT function */
# asm
MOV CX,DS ; store DS in CX
PUSH DS ; save DS
MOV AX,0 ; this will be new value for DS
MOV DS,AX ; put 0 in DS
MOV WORD [04FAH], CX ; store DS
POP DS ; retrieve DS
#
/* MIDInterface 1.11 16-track digital sequencer
Data storage format:
--------------------
(MIDI ORIENTED COMMANDS)
byte num: first second third fourth fifth
+--------+----------+----------+----------+--------+
Note ON 00vvvvvv | LLLLLLLL | MMMMMMMM | 1nnnnnnn | --
| | | |
Note OFF 00vvvvvv | LLLLLLLL | MMMMMMMM | 0nnnnnnn | --
| | | |
Prog Chan 01000000 | LLLLLLLL | MMMMMMMM | 0ppppppp | --
| | | |
Chan Pres 01000001 | LLLLLLLL | MMMMMMMM | 0aaaaaaa | --
(after-touch) | | | |
Pitch Wheel 10wwwwww | LLLLLLLL | MMMMMMMM | -- | --
| | | |
Cntrl Chan 11000000 | LLLLLLLL | MMMMMMMM | 0nnnnnnn | 0ccccccc
| | | |
Key Pres. 011vvvvv | LLLLLLLL | MMMMMMMM | 0nnnnnnn | --
(after-touch)
(INTERNAL ORIENTED COMMANDS)
+--------+----------+----------+----------+--------+
Change Tempo 11000001 | LLLLLLLL | MMMMMMMM | tttttttt | --
End 11111111 | -- | -- | -- | --
-------------------------------------------------------------------------
vvvvvv - top 6 bits of velocity (NOTE ON or OFF)
LLLLLLLL - LSB of clk
MMMMMMMM - MSB of clk
nnnnnnn - note for either NOTE ON or NOTE OFF
ppppppp - new program
aaaaaaa - chan pressure (after-touch)
wwwwww - top six of bender
nnnnnnn - control number
ccccccc - control value
tttttttt - new tempo value (40-200)
*/
c=0;
while(c<79)
sin_line[c++]='─';
sin_line[c]='\0';
in_filt=0xff; /* Don't filter out anything */
clk_type=0; /* internal */
counter_dec=2;
rbuff=255;
segment[0]=segment[1]=_showds(); /* 1st two buffs in DS */
startp[0]=buff1; endp[0]=buff1+Tsize-8;
startp[1]=buff2; endp[1]=buff2+Tsize-8;
parts[0].ssize=0; parts[1].ssize=0;
/* This is the memory allocation section.
This is really a sort of pseudo-allocation scheme
allowing the use of the entire system memory (up to 640K).
Memory is allocated in blocks of 25k (1600 paragraphs).
All tracks are allocated sequentially until you run out
of system RAM. The first two tracks are taken care of
in the C memory, so there should always be room for these.
*/
base_seg=_showss()+1; /* start just after stack */
base_seg += (_showsp()/16); /* This is the segment boundary of
the bottom of un-initialized mem */
++base_seg; /* one for a safety */
cont_mem=get_av_mem();
cont_mem *= 64; /* Find total # of system para. */
/* Here's where we "allocate our memory" */
_setmem(segment+4,28,0);
c=2;
for (a=base_seg; a < cont_mem && c < 16; a+=seg_per_trk) {
segment[c]=a;
startp[c]=0;
endp[c]=Tsize-8;
parts[c].ssize=0;
parts[c].transpose=0;
++c;
}
m_t_b=2; s_t_b=1; a_t_b=48; /* default time bases */
printer=0;
scr_cla();
printf("Do you wish to use the printer as an audio meternome?");
if(toupper(getchar())=='Y') {
printf("\nReady the printer and hit any key");
getchar();
if((pfd=open("PRN",2))==-1) {
printf("Error opening printer ... aborting\n");
getchar();
exit(1);
}
beepp();
printer=1;
}
start:
setdart();
intoff(); /* turn interrupts off */
scr_cla();
printf(" ╔════════════════════════════════════════════════╗\n");
printf(" ║ MIDInterface 1.11 16 Track Digital Recorder ║\n");
printf(" ╚════════════════════════════════════════════════╝\n");
printf("\n");
printf(" Main Menu:\n");
printf(" ──────────\n");
printf(" 1..........Erase a track\n");
printf(" 2..........Record to a track\n");
printf(" 3..........Play from a track\n");
printf(" 4..........Track information\n");
printf(" 5..........Save a track\n");
printf(" 6..........Load a track\n");
printf(" 7..........Set MIDI modes\n");
printf(" 8..........Edit input filter\n");
printf(" 0..........Quit\n");
scr_rowcol(24,0);
printf(" Copyright (C) 1985, 1986 by Jay Kubicky");
scr_rowcol(18,0);
printf(" Enter Selection:");
sel=getchar();
switch (sel) {
case '1':
erbuff();
break;
case '2':
recbuff();
break;
case '3':
pbuffs();
break;
case '4':
dbuffs();
break;
case '5':
strack();
break;
case '6':
ltrack();
break;
case '7':
mmode();
break;
case '8':
ed_in_filt();
break;
case '0':
scr_cla();
b=0;
for(a=0; a<16; ++a) {
if(parts[a].ssize) {
b=1; /* toggle high */
printf(" Data still left in track %d\n",a);
}
}
if(!b) {
close(pfd);
exit(0);
}
printf("Still want to exit? ");
if(toupper(getchar()) == 'Y') {
close(pfd);
exit(0);
}
default:
goto start;
}
goto start;
}
/* DBUFFS
This is the general buffer display routine.
It displays all pertinent data for all avaiable buffers.
*/
dbuffs()
{
char a,b; unsigned tn,nf,nu;
s_: scr_cla();
printf(" Track Assignment Screen:\n");
printf(" ════════════════════════\n");
printf("Track Num: Transmit Chan: Notes Used: Transpose: Enabeled:\n");
printf("%s\n",sin_line);
for(a=0; a<16; ++a) {
if(segment[a]) {
tn=(endp[a]-startp[a])/8;
nf=tn-(parts[a].ssize/8);
nu=tn-nf;
b=parts[a].transpose;
printf("%d\t\t%d\t\t%d\t\t%d\t\t%s\n",a,parts[a].chan,nu,b < 128 ? b : -256+b, buffon[a] || (a==rbuff) ? yes : no);
}
else
printf("--\t\t--\t\t--\t\t--\t\t--\n");
}
printf("%s\n",sin_line);
ttag: scr_rowcol(21,0);
printf("Change one trans. channel (1), change all (2), transpose(3), enable status (4)\n");
printf("or (0) to quit/continue: ");
a=getchar();
scr_rowcol(22,17);
scr_cls(); /* clear rest of current line */
switch(a) {
case '0':
return;
break;
case '1':
printf(" Enter track number:");
b=getint();
scr_rowcol(23,0);
printf(" Enter new transmit channel:");
parts[b].chan=getint();
break;
case '2':
printf(" Enter new transmit channel for all tracks:");
a=getint();
for(b=0; b<16; ++b)
parts[b].chan=a;
break;
case '3':
printf(" Enter track number:");
b=getint();
scr_rowcol(23,0);
printf(" Enter new transpose amount:");
parts[b].transpose=getint();
break;
case '4':
printf(" Enter track number:");
b=getint();
if(parts[b].ssize && b != rbuff)
buffon[b]= buffon[b] ? 0 : 1;
break;
default:
goto ttag;
}
goto s_;
}
/* ERBUFF
This funct. erase a buffer (set the size to 0)
*/
erbuff()
{
scr_cla();
char b;
printf(" Erase a Track\n");
printf("%s\n",sin_line);
printf("\nWhich buffer? ");
b=getint();
printf("Are you sure you want to erase buffer %d?",b);
if(toupper(getchar()) != 'Y')
return;
parts[b].ssize=0;
buffon[b]=0;
}
/* PBUFFS
This is the top-level play-buffer routine.
*/
pbuffs()
{
int m;
copyptrs();
scr_cla();
printf(" Play Track Mode\n");
printf("%s\n\n\n",sin_line);
printf(" Hit any key to continue\n");
getchar();
dbuffs();
scr_cla();
printf(" Play Track Mode\n");
printf("%s\n\n\n",sin_line);
get_options();
printf("\nHit space bar to continue, any other key to quit\n");
if(getchar()!=32)
return;
setrec();
destbyte=0xff;
play();
intoff();
_outb(5,MIDIS); /* send off to drum mach. */
_outb(104,MIDIS);
_outb(0xfc,MIDID); /* MIDI seq off */
for(m=0; m<16; ++m) {
if(parts[m].ssize)
buffon[m]=1;
}
}
/*
RECBUFF:
This is the track record routine.
All it really does is set up & enable the interrupt routine -
RxInt
*/
recbuff()
{
char b; int m;
copyptrs();
scr_cla();
printf(" Record a Track\n");
printf("%s\n\n",sin_line);
printf(" Which buffer:");
b=getint();
if(parts[b].ssize) {
printf("That buffer already has music, still want to record (Y/N)?");
if(toupper(getchar()) != 'Y')
return;
}
if(!segment[b]) {
printf("Sorry, that track is not available to record in.\n");
hak();
return;
}
rbuff=b;
parts[b].ssize=0;
dbuffs(); /* display buff enable board w/ option to change */
scr_cla();
get_options();
printf("\nHit any key to begin recording\n");
getchar();
scr_cla();
printf("Hit any key to stop recording\n");
setrec();
play();
_poke(255,ptr,segment[rbuff]); /* EOS (end-of-song) */
parts[b].ssize=ptr-startp[rbuff];
printf("\nSong is %d notes long\n",parts[b].ssize / 8);
rbuff=255; /* no more record buffer */
pointers[b]=startp[b]; /* copy start pointer */
buffon[b]=1; /* enable present buffer */
_outb(5,MIDIS); /* send off to drum mach. */
_outb(104,MIDIS);
_outb(0xfc,MIDID); /* MIDI seq off */
rbuff=0xff;
hak();
}
/* SETREC
This sets up almost everything for Play & Record.
*/
setrec()
{
int a;
stop=0;
destbyte=0;
setint();
ptr=startp[rbuff];
end=endp[rbuff];
r_segment=segment[rbuff];
end=endp[rbuff];
C_O_F=0x90;
beat=abeat=mbeat=0xfe;
if(dsync) {
_outb(5,MIDIS); /* send start to drums */
_outb(104+128,MIDIS);
}
if(MIDIsync)
_outb(0xfa,MIDID); /* start ext seq */
pointers[0]=startp[0];
pointers[1]=startp[1];
setcounter(tempo & 0xff,tempo >> 8,255,255);
}
copyptrs() /* copy start pstns of buffers into pointer areas */
{
char a;
for(a=0; a<15; ++a)
pointers[a]=startp[a];
}
/* LTRACK
Load a track into memory.
*/
ltrack()
{
char tr;
scr_cla();
printf(" Load a Track\n");
printf("%s\n",sin_line);
dir("????????","???");
scr_rowcol(2,0);
printf(" Load which track:");
tr=getint();
if(parts[tr].ssize) {
printf("Data already in that track ... aborting.\n");
getchar(); return; }
printf(" Load from which file:");
scanf("%s",filename);
if((fd=open(filename,2)) == -1) {
printf("Can't open %s ... aborting\n",filename);
getchar();
return;
}
if(read(fd,parts[tr],63) == -1) {
printf("Error encountered during reading.\n");
getchar();
return;
}
if(seg_read(fd,tr,parts[tr].ssize+1) == -1) {
printf("Error encountered while reading.\n");
getchar(); return; }
close(fd);
printf("Total bytes loaded from disk:%d\n",parts[tr].ssize+63);
buffon[tr]=1;
getchar();
}
/* STRACK
Save a track to disk.
*/
strack() /* save a track */
{
char tr;
scr_cla();
printf(" Save a Track\n");
printf("%s\n",sin_line);
dir("????????","???");
scr_rowcol(2,0);
printf(" Save which track:");
tr=getint();
if(!parts[tr].ssize) {
printf("Nothing in that track ... aborting.\n");
getchar(); return; }
printf(" Save to what file:");
scanf("%s",filename);
if((fd=creat(filename)) == -1) {
printf("Can't creat %s ... aborting\n",filename);
getchar();
return;
}
if(write(fd,parts[tr],63) == -1) {
printf("Error encountered during writing.\n");
getchar();
goto _end;
}
if(seg_write(fd,tr,parts[tr].ssize+1) == -1) {
printf("Error encountered while writing.\n");
getchar(); goto _end; }
close(fd);
printf("Total bytes written to disk:%d\n",parts[tr].ssize+63);
hak();
return;
_end:
close(fd);
}
/* SEG_READ, SEG_WRITE
These functions carry out intra-segmentary disk I/O functions.
*/
seg_read(fd,tr,size)
int fd, tr; unsigned size;
{
unsigned a;
a=startp[tr]; /* this won't be 0 for tr. 0 & 1 : it's a pointer */
if(size > 1024) {
size+=a; /* make size look like a pointer */
for(;a < (size-1024); a+=1024) {
if(read(fd,vir_buff,1024) == -1)
return(-1);
_lmove(1024,vir_buff,_showds(),a,segment[tr]);
}
}
else
size+=a;
if(!(size-a))
return(1);
if(read(fd,vir_buff,size-a) == -1)
return(-1);
_lmove(size-a,vir_buff,_showds(),a,segment[tr]);
return(1);
}
seg_write(fd,tr,size)
int fd, tr; unsigned size;
{
unsigned a;
a=startp[tr]; /* this won't always be 0 because of tracks 0 & 1 */
if(size > 1024) {
size+=a; /* make size look like a pointer */
for(;a < (size-1024); a+=1024) {
_lmove(1024,a,segment[tr],vir_buff,_showds());
if(write(fd,vir_buff,1024) == -1)
return(-1);
}
}
else
size+=a;
if(!(size-a)) /* Is the buff length 0 || have we written all data? */
return(1);
_lmove(size-a,a,segment[tr],vir_buff,_showds());
if(write(fd,vir_buff,size-a) == -1)
return(-1);
return(1);
}
/* play() -
This function plays through the 16 tracks until track 0 ends
or a key is struck.
*/
play()
{
int playing;
char a,ch,b;
unsigned n;
scr_rowcol(2,0);
printf("Tempo: %d",r_tempo);
sp:
for (a=0; a<15; ++a) {
if(buffon[a] && a!=rbuff) {
if(playfrom(a)) { /* Track or song end */
if(a) /* if not track 0 */
buffon[a]=0; /* turn off buff */
else
return;
}
}
if(dsync)
bt();
if(MIDIsync)
bt2();
if(audmet)
bt3();
}
if(!(ch=scr_csts()))
goto sp;
else {
switch(ch) {
case '+':
++r_tempo;
break;
case '-':
--r_tempo;
break;
default:
return;
}
scr_rowcol(2,10);
printf("%d",r_tempo);
tempo=2000000/((r_tempo*48)/60);
set_cnt_1(tempo,tempo >> 8);
}
goto sp;
}
playfrom(a)
char a;
{
char *p,d,*p1;
p=vir_buff;
_lmove(8,pointers[a],segment[a],vir_buff,_showds());
if(*p==0xff) /* check for EOS */
return(1);
readclk();
p1=p+2;
if(*p1 > cmsb)
goto pnow;
if(*p1 < cmsb)
return(0);
if(*(p+1) < clsb)
return(0);
pnow: /* now we know that it's time to play [notes]... */
d=*p & 0xc0;
switch(d) {
case 00: /* note on or off */
pnt(p,parts[a].chan,parts[a].transpose);
pointers[a]+=4;
break;
case 0x40: /* prog chan / chan pres. / key pres. */
pchan(p,parts[a].chan);
pointers[a]+=4;
break;
case 0x80: /* pitch bender */
w_f_e(); /* let FIFO empty */
_outb(0xE0+parts[a].chan,MIDID); /* send P. B. code */
w_f_e(); /* let FIFO empty */
_outb(0,MIDID); /* we didn't store LSB */
w_f_e();
_outb(*p << 1,MIDID); /* send MSB */
pointers[a]+=3;
break;
case 0xC0: /* cntrl chan | temp chan */
cchan(p,parts[a].chan);
if(!(*p&1)); /* make up for control change */
++pointers[a];
pointers[a]+=4;
break;
}
return(0);
}
pnt(p,tc,trans)
char *p,tc,trans;
{
# asm
MOV SI,WORD [BP+4] ; get p
MOV AL,BYTE [SI+3] ; get *(p+3)
AND AL,128 ; strip off top bit
JZ znoff ; play a note off
MOV AL,BYTE [BP+6] ; get tchan
ADD AL,090H ; add a basic note on
zcheat1: ; here's where we'll cheat on a Note OFF
MOV DX,0FFA0H ; MIDI Data port
CALL w_f_e_ ; wait for DART FIFO to empty
OUT DX,AL ; send byte
MOV AL,BYTE [SI+3] ; get note to turn on
ADD AL,BYTE [BP+8] ; add transpose val.
AND AL,07FH ; strip off top bit
CALL w_f_e_ ; wait for DART FIFO to empty
OUT DX,AL ; send out note
MOV AL,BYTE [SI] ; get velocity
SHL AL,1 ; shift up into range
CALL w_f_e_ ; wait for DART FIFO to empty out
OUT DX,AL ; send velocity
JMP zalldone ; finished
znoff: ; send Note OFF command
MOV AL,BYTE [BP+6] ; get transmit channel
ADD AL,080H ; add basic Note OFF
JMP zcheat1 ; let's take a short cut
zalldone: ; all done
#
}
pchan(p,tc) /* Program change, channel pressure, or after-touch */
char *p,tc;
{
# asm
MOV DX,0FFA0H ; DART port
MOV SI,WORD [BP+4] ; get p
MOV AL,BYTE [SI] ; get I.D. byte
CMP AL,040H ; I.D. for Prog change
JZ zpchan ; branch if Prog change
CMP AL,041H ; I.D. for Chan pressure, after-touch
JZ zchanp
; else, Poly. key press. (after-touch)
MOV AL,BYTE [BP+6] ; get transmit chan
ADD AL,0A0H ; poly. key pressure
CALL w_f_e_
OUT DX,AL ; send 1st byte
MOV AL,BYTE [SI+3] ; get key #
CALL w_f_e_
OUT DX,AL
MOV AL,BYTE [SI] ; get pressure
AND AL,01FH ; strip off bottom 5
SHL AL,1
SHL AL,1 ; bumb up two bits
CALL w_f_e_
OUT DX,AL
JMP zalldone2 ; all done
zpchan: ; program change
MOV AL,BYTE [BP+6] ; get transmit channel
ADD AL,0C0H ; basic prog chan
JMP zcheat2 ; use code from above routine
zchanp: ; channel pressure
MOV AL,BYTE [BP+6] ; get transmit channel
ADD AL,0D0H ; add basic chan pres
JMP zcheat2
zcheat2: ; entry point from zpchan
CALL w_f_e_ ; wait for DART
OUT DX,AL ; send byte
MOV AL,BYTE [SI+3] ; get new vel
OUT DX,AL ; send
zalldone2: ; FINE
#
}
cchan(p,tc)
char *p,tc;
{
# asm
MOV SI,WORD [BP+4] ; get p
MOV AL,BYTE [SI] ; get I.D. byte
AND AL,1 ; bit 0
JNZ ztchan ; tempo change
; now we know it's a cntrl chan
MOV AL,0B0H ; cntrl chan
ADD AL,BYTE [BP+6] ; add transmit channel
MOV DX,0FFA0H ; MIDID port
CALL w_f_e_ ; wait for DART to empty
OUT DX,AL
MOV AL,BYTE [SI+3] ; get cntrl #
CALL w_f_e_ ; wait for DART FIFO to empty
OUT DX,AL
MOV AL,BYTE [SI+4] ; get cntrl val
CALL w_f_e_
OUT DX,AL
JMP _fine2 ; done
ztchan: ; tempo change
; MOV AL,extsync_
; OR AL,AL ; set flags
; JNZ _fine2 ; if extsync mode, then this has no purpose
#
/* tempo(*(p+3)+30); */
# asm
_fine2:
#
}
w_f_e() /* this function "sleeps" until the FIFO in the DART is empty */
{
# asm
PUSH DX
PUSH AX
MOV DX,0FFA2H ; DART status register
try_again:
IN AL,DX
AND AL,4 ; Tx buff empty?
JZ try_again ; no?
POP AX
POP DX
#
}
/*
BT, BT2, BT3
These are the meternome counting routines.
*/
bt()
{
readclk();
if(beat==clsb) {
_outb(5,MIDIS+1); /* send sync high */
_outb(128,MIDIS+1);
_outb(5,MIDIS+1); /* send sync low */
_outb(0,MIDIS+1);
beat-=s_t_b;
}
}
bt2()
{
readclk();
if(mbeat==clsb) {
_outb(0xf8,MIDID); /* MIDI timing clk */
mbeat-=m_t_b;
}
}
bt3()
{
readclk();
if(abeat==clsb) {
if(printer)
beepp();
abeat-=a_t_b;
}
}
beepp()
{
_rax=0x0500;
_rdx=7;
_doint(0x21);
}
/* SETINT
This routine sets up the interrupt.
*/
setint()
{
int rxint(),a;
int seg_num, (*fun_add)();
fun_add = rxint;
seg_num=_showcs();
_poke(fun_add & 0xff,0x28,0); _poke(fun_add >> 8,0x29,0);
_poke(seg_num & 0xff,0x2a,0); _poke(seg_num >> 8,0x2b,0);
setdart();
setpic();
}
setdart()
{
_outb(24,MIDIS); /* reset channel A */
_outb(1,MIDIS); _outb(24,MIDIS); /* int on all Rx + Ext Stat */
_outb(3,MIDIS); _outb(193,MIDIS);
_outb(4,MIDIS); _outb(196,MIDIS);
_outb(5,MIDIS); _outb(104,MIDIS);
}
setpic()
{
char a;
a=_inb(PIC1); /* read interrupt mask */
if(a&4) /* if DART is masked off */
a-=4;
_outb(a,PIC1); /* re-enable ints */
}
setcounter(l1,m1,l2,m2)
char l1,m1,l2,m2;
{
char e,d;
_outb(0x34,CSTAT); /* counter 1=mode 2 - read/load both */
e=d; d=e;
_outb(0x70,CSTAT); /* counter 2= mode 0 - read/load both */
e=d; d=e;
_outb(l2,COUNTER2); /* set LSB of counter 2 */
e=d; d=e;
_outb(m2,COUNTER2); /* set MSB of counter 2 */
e=d; d=e;
_outb(l1,COUNTER1); /* set LSB of counter 1 */
e=d; d=e;
_outb(m1,COUNTER1); /* set MSB of counter 1 */
readclk();
while(cmsb!=255 && clsb!=255)
readclk();
return;
}
set_cnt_1(l1,m1)
char l1,m1;
{
_outb(l1,COUNTER1); /* set LSB of counter 1 */
_outb(m1,COUNTER1); /* set MSB of counter 1 */
}
intoff()
{
_outb(01,MIDIS); /* turn off my interrupt */
_outb(00,MIDIS); /* (at the DART) */
}
inton()
{
_outb(01,MIDIS); /* turn on my interrupt */
_outb(24,MIDIS); /* (at the DART) */
}
readclk()
{
# asm
MOV AL,64
MOV DX,0FFA7H
CLI ; an interrupt right now from Rxint would be bad
OUT DX,AL
NOP
NOP
NOP
SUB DX,2
IN AL,DX
MOV clsb_,AL
NOP
NOP
NOP
IN AL,DX
MOV cmsb_,AL
STI ; ints back on
#
}
scr_cla() /* clear screen & pstn cursor at top */
{
scr_clr();
scr_rowcol(0,0);
}
/* MMODE
This is a no-frills routine for setting up various
MIDI system modes
*/
mmode()
{
char a,mo,v;
st:
scr_cla();
printf(" MIDI mode assignments:\n");
printf("%s\n",sin_line);
ss:
putchar('\n');
printf(" 1 - Omni ON / Poly\n");
printf(" 2 - Omni OFF / Poly\n");
printf(" 3 - Omni ON / Mono\n");
printf(" 4 - Omni OFF / Mono\n");
printf(" 5 - Program change\n");
printf(" 6 - All notes off (all channels)\n");
printf(" 7 - All notes off (one channel)\n");
printf(" 0 - Exit\n");
printf("Enter new mode:");
mo=getint();
if(!mo)
return;
if(mo>7)
goto st;
if(mo==6)
goto skip;
printf("Send over which channel:");
a=getint(); if(a > 15)
goto ss;
printf("\nChannel %d:\n",a);
skip:
switch(mo) {
case 1:
printf(" Poly / Omni on\n");
poly(a);
o_on(a);
break;
case 2:
printf(" Poly / Omni off\n");
poly(a);
omni_off(a);
break;
case 3:
printf(" Mono / Omni on\n");
mono(a);
o_on(a);
break;
case 4:
printf(" Mono / Omni off\n");
mono(a);
omni_off(a);
break;
case 5:
printf(" Program change\n");
printf(" Enter new program: ");
v=getint();
_outb(192+a,MIDID);
_outb(v,MIDID);
break;
case 6:
for(a=0; a<16; ++a) {
_outb(0xb0+a,MIDID);
_outb(123,MIDID);
w_f_e();
_outb(0,MIDID);
}
printf(" All notes off - all channels\n");
getchar();
break;
case 7:
_outb(0xb0+a,MIDID);
_outb(123,MIDID);
w_f_e();
_outb(0,MIDID);
printf(" All notes off\n");
getchar();
break;
}
goto st;
}
o_on(ch)
char ch;
{
_outb(176+ch,MIDID);
_outb(125,MIDID);
w_f_e();
_outb(0,MIDID);
getchar();
}
omni_off(ch)
char ch;
{
_outb(176+ch,MIDID);
_outb(124,MIDID);
w_f_e();
_outb(0,MIDID);
getchar();
}
poly(ch)
char ch;
{
_outb(176+ch,MIDID);
_outb(127,MIDID);
w_f_e();
_outb(0,MIDID);
getchar();
}
mono(ch)
char ch;
{
char v;
printf("How many channels? (0 = # in receiver, or other) ");
v=getint();
_outb(176+ch,MIDID);
_outb(126,MIDID);
w_f_e();
_outb(v,MIDID);
getchar();
}
get_av_mem() /* returns total system RAM - in K */
{
_doint(0x012);
return(_rax);
}
char *_showss()
{
# asm
MOV AX,SS
#
}
hak() /* display "hit any key to continue" & wait */
{
puts("\n\n");
scr_cls();
puts(" Hit any key to continue.");
while(!scr_csts());
}
getint() /* error check an input line & return int */
{
char inln[20],*b,flag;
stg:
_gets(inln,20);
if(strlen(inln)) {
for(b=inln;*b!='\0';++b) {
if(!isdigit(*b) && *b != '-') {
putchar(7);
goto stg;
}
}
return(atoi(inln));
}
else
putchar(7);
goto stg;
}
/* ED_IN_FILT
This routine allows the user to edit the input filter
*/
ed_in_filt()
{
int n;
scr_cla();
scr_rowcol(0,26);
printf("Edit Input Filter\n");
printf("%s\n\n",sin_line);
st_filt:
scr_rowcol(3,0);
printf(" Mess #: Message type: Status:\n");
printf(" ──────────┬────────────────────────┬───────────\n");
printf(" 1 │ Note ON │ %s\n",(in_filt & 1) ? yes : no);
printf(" 2 │ Note OFF │ %s\n",(in_filt & 2) ? yes : no);
printf(" 3 │ Program Change │ %s\n",(in_filt & 4) ? yes : no);
printf(" 4 │ Channel Pressure │ %s\n",(in_filt & 8) ? yes : no);
printf(" 5 │ Pitch Wheel │ %s\n",(in_filt & 16) ? yes : no);
printf(" 6 │ Control Change │ %s\n",(in_filt & 32) ? yes : no);
printf(" 7 │ Poly. Key Pressure │ %s\n",(in_filt & 64) ? yes : no);
printf(" ──────────┴────────────────────────┴───────────\n");
printf("\n\n\n\n\n");
re_try:
scr_rowcol(18,12);
printf("Enter Message Number to toggle, 0 to end: ");
n=getint();
if(n<0 || n>7)
goto re_try;
if(!n)
return;
n=1 << (n-1); /* make n into bit to complement */
in_filt = in_filt & n ? in_filt-n : in_filt+n;
goto st_filt;
}
get_options() /* enter various user options */
{
em: printf("Enter metrenome speed:");
r_tempo=getint();
if(r_tempo<40 || r_tempo>200)
goto em;
tempo=2000000/((r_tempo*48)/60);
printf("Audio Sync (Y/N):");
audmet=(toupper(getchar())=='Y') ? 1:0;
putchar('\n');
printf("Drum Sync (Y/N):");
dsync=(toupper(getchar())=='Y') ? 1:0;
putchar('\n');
printf("MIDI Sync (Y/N):");
MIDIsync=(toupper(getchar())=='Y') ? 1:0;
}
/* dir(fname,ext)
char *fname,*ext;
This function shows a directory of the currently logged directory
and disk and print it on the screen in "five-across" format.
*/
dir(fname,ext) /* function to show directory of currently logged disk & dir */
char *fname,*ext; /* pointers to filename & extension */
{
struct fcb {
char drive_num;
char filename[8];
char extension[3];
char rest[25]; /* the rest of the fcb */
} fcb;
struct fcb fcb2;
unsigned dta_add, dta_seg;
char filename[21];
char flag=4;
char cnt=80;
fcb.drive_num=0;
strcpy(filename," ");
strncpy(fcb.filename,fname,8);
strncpy(fcb.extension,ext,3);
_setmem(fcb.rest,25,0);
_rax=0x2f00; /* get current DTA */
_doint(0x21);
dta_add=_rbx;
dta_seg=_res; /* this is the offset & segment of the current DTA */
_rdx=fcb;
_rds=_showds();
_rax=0x1100;
scr_rowcol(6,0);
printf("%s\n",sin_line);
scr_rowcol(7,0);
scr_cls();
for(;;) {
_doint(0x21);
if((_rax & 0xff))
break; /* last file has been listed */
_lmove(20,dta_add,dta_seg,fcb2,_showds());
strncpy(filename,fcb2.filename,8);
filename[8]='.';
filename[9]='\0';
strcat(filename,fcb2.extension);
filename[12]='\0';
puts(filename);
puts(" ");
if(!flag)
flag=5;
if(!--cnt) {
printf(" Hit any key to continue.");
getchar();
scr_rowcol(7,0);
scr_cls();
cnt=80;
flag=4;
}
--flag;
_rax=0x1200;
}
}